package cn.com.pusai.common.dao.impl;

import cn.com.pusai.common.dao.BaseDAO;
import cn.com.pusai.common.util.SearchMap;
import cn.com.pusai.core.util.ClassTypeUtil;
import cn.com.pusai.core.util.VType;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * 底层操作类
 * */
public abstract class BaseDAOHibernate extends HibernateDaoSupport
    implements BaseDAO
{

    protected abstract Class getEntityClass();

    public BaseDAOHibernate()
    {
    }

    public Object findObjectById(Serializable id)
    {
        return findObjectById(id, getEntityClass());
    }

    public Object findObjectById(Serializable id, Class objectClass)
    {
        return getHibernateTemplate().get(objectClass, id);
    }

    public void delete(Object object)
    {
        getHibernateTemplate().delete(object);
    }

    public void delete(Serializable id)
    {
        delete(id, getEntityClass());
    }

    public void delete(Serializable id, Class objectClass)
    {
        Session session = getSession();
        Object object = findObjectById(id, objectClass);
        if(object != null)
            delete(object);
    }

    public void delete(Serializable ids[])
    {
        for(int i = 0; i < ids.length; i++)
            delete(ids[i]);

    }

    public void delete(Serializable ids[], Class objectClass)
    {
        for(int i = 0; i < ids.length; i++)
            delete(ids[i], objectClass);

    }

    public void update(Object object)
    {
        getHibernateTemplate().update(object);
    }

    public void updateObjectProperty(Serializable id, String propertyName, Object propertyValue, Class objectClass)
    {
        updateObjectProperty(new Serializable[] {
            id
        }, new String[] {
            propertyName
        }, new Object[] {
            propertyValue
        }, objectClass);
    }

    public void updateObjectProperty(Serializable ids[], String propertyName, Object propertyValue, Class objectClass)
    {
        updateObjectProperty(ids, new String[] {
            propertyName
        }, new Object[] {
            propertyValue
        }, objectClass);
    }

    public void updateObjectProperty(Serializable id, String propertyNames[], Object propertyValues[], Class objectClass)
    {
        updateObjectProperty(new Serializable[] {
            id
        }, propertyNames, propertyValues, objectClass);
    }

    public void updateObjectProperty(Serializable ids[], String propertyNames[], Object propertyValues[], Class objectClass)
    {
        if(ids == null || ids.length <= 0)
            return;
        StringBuffer sb = new StringBuffer("'");
        for(int i = 0; i < ids.length; i++)
        {
            sb.append(ids[i]);
            sb.append("','");
        }

        String idsString = sb.toString().substring(0, sb.toString().length() - 2);
        StringBuffer HQL = new StringBuffer((new StringBuilder("update ")).append(objectClass.getName()).append(" set ").toString());
        Map whereMap = new HashMap();
        if(propertyNames != null && propertyValues != null && propertyNames.length == propertyValues.length)
        {
            for(int i = 0; i < propertyNames.length; i++)
            {
                if(i != 0)
                    HQL.append(",");
                HQL.append(propertyNames[i]);
                HQL.append("=:propertyValue");
                HQL.append(i);
            }

        }
        if(ids.length == 1)
        {
            HQL.append(" where id=:id");
            whereMap.put("id", ids[0]);
        } else
        {
            HQL.append((new StringBuilder(" where id in(")).append(idsString).append(")").toString());
        }
        for(int i = 0; i < propertyNames.length; i++)
            whereMap.put((new StringBuilder("propertyValue")).append(i).toString(), propertyValues[i]);

        updateJQL(HQL.toString(), whereMap);
    }

    public void create(Object object)
    {
        getHibernateTemplate().save(object);
    }

    public List findObjects(SearchMap searchMap)
    {
        return findObjects(-1, -1, searchMap, getEntityClass());
    }

    public List findObjects(SearchMap searchMap, Class objectClass)
    {
        return findObjects(-1, -1, searchMap, objectClass);
    }

    public List findObjects(int pageNo, int maxPageSize, SearchMap searchMap)
    {
        return findObjects(pageNo, maxPageSize, searchMap, getEntityClass());
    }

    public List findObjects(int pageNo, int maxPageSize, SearchMap searchMap, Class objectClass)
    {
        String HQL = String.format("from %s as a ", new Object[] {
            objectClass.getName()
        });
        List list = getList(HQL, searchMap, pageNo, maxPageSize);
        return list;
    }

    public long getCount(SearchMap searchMap)
    {
        return getCount(searchMap, getEntityClass());
    }

    public long getCount(SearchMap searchMap, Class objectClass)
    {
        long count = 0L;
        String HQL = String.format("select count(*) from %s as a  ", new Object[] {
            objectClass.getName()
        });
        List list = getList(HQL, searchMap, -1, -1);
        if(list != null && list.size() > 0)
            count = ((Number)list.get(0)).longValue();
        return count;
    }

    public List findObjects(String jql, Map whereMap)
    {
        return findObjects(jql, whereMap, -1, -1);
    }

    public List findObjects(String jql, Map whereMap, int pageNo, int maxPageSize)
    {
        Session session = super.getSession();
        Query query = null;
        query = session.createQuery(jql);
        if(whereMap != null)
        {
            String whereKey;
            Object whereValue;
            for(Iterator it = whereMap.keySet().iterator(); it.hasNext(); query.setParameter(whereKey, whereValue))
            {
                whereKey = (String)it.next();
                whereValue = whereMap.get(whereKey);
            }

        }
        if(pageNo != -1 || maxPageSize != -1)
        {
            query.setFirstResult((pageNo - 1) * maxPageSize);
            query.setMaxResults(maxPageSize);
        }
        query.setCacheable(true);
        List list = query.list();
        return list;
    }

    public Object findObject(String jql, Map whereMap)
    {
        List list = findObjects(jql, whereMap, -1, -1);
        if(list.size() > 0)
            return list.get(0);
        else
            return null;
    }

    public List findObjects(String jql)
    {
        return findObjects(jql, ((Map) (null)));
    }

    public List findObjects(int pageNo, int maxPageSize, String HQL)
    {
        return findObjects(HQL, ((Map) (null)), pageNo, maxPageSize);
    }

    public Object findObject(String jql)
    {
        return findObject(jql, null);
    }

    public long getCount(String jql)
    {
        Map map = null;
        return getCount(jql, map);
    }

    public long getCount(String jql, Map whereMap)
    {
        long count = 0L;
        List list = findObjects(jql, whereMap);
        if(list != null && list.size() > 0)
            count = ((Number)list.get(0)).longValue();
        return count;
    }

    public long getCount(String jql, SearchMap whereMap)
        throws Exception
    {
        long count = 0L;
        List list = getList(jql, whereMap);
        if(list != null && list.size() > 0)
            count = ((Number)list.get(0)).longValue();
        return count;
    }

    public void updateJQL(String jql, Map whereMap)
    {
        Session session = getSession();
        Query query = session.createQuery(jql);
        if(whereMap != null)
        {
            String whereKey;
            Object whereValue;
            for(Iterator it = whereMap.keySet().iterator(); it.hasNext(); setQueryValue(query, whereKey, whereValue))
            {
                whereKey = (String)it.next();
                whereValue = whereMap.get(whereKey);
            }

        }
        query.executeUpdate();
    }

    private static void setQueryValue(Query query, String parmName, Object parmValue)
    {
        switch(swicthUtilVType()[ClassTypeUtil.getVType(parmValue).ordinal()])
        {
        case 6: // '\006'
            query.setString(parmName, (String)parmValue);
            break;

        case 4: // '\004'
            query.setBigDecimal(parmName, (BigDecimal)parmValue);
            break;

        case 5: // '\005'
            query.setBoolean(parmName, ((Boolean)parmValue).booleanValue());
            break;

        case 12: // '\f'
            query.setByte(parmName, ((Byte)parmValue).byteValue());
            break;

        case 13: // '\r'
            query.setShort(parmName, ((Short)parmValue).shortValue());
            break;

        case 7: // '\007'
            query.setDate(parmName, (Date)parmValue);
            break;

        case 11: // '\013'
            query.setTimestamp(parmName, new Timestamp(((java.util.Date)parmValue).getTime()));
            break;

        case 3: // '\003'
            query.setDouble(parmName, ((Double)parmValue).doubleValue());
            break;

        case 2: // '\002'
            query.setFloat(parmName, ((Float)parmValue).floatValue());
            break;

        case 1: // '\001'
            query.setInteger(parmName, ((Integer)parmValue).intValue());
            break;

        case 10: // '\n'
            query.setLong(parmName, ((Long)parmValue).longValue());
            break;

        case 8: // '\b'
            query.setTimestamp(parmName, (Timestamp)parmValue);
            break;
        }
    }

    private List getList(String HQL, SearchMap searchMap)
        throws Exception
    {
        return getList(HQL, searchMap, -1, -1);
    }

    public List getList(String HQL, SearchMap searchMap, int pageNo, int maxPageSize)
    {
        Session session = getSession();
        String tempHQL = getSQL(HQL, searchMap);
        Query query = session.createQuery(tempHQL.toString());
        searchMap.setQuery(query);
        if(pageNo != -1 || maxPageSize != -1)
        {
            query.setFirstResult((pageNo - 1) * maxPageSize);
            query.setMaxResults(maxPageSize);
        }
        query.setCacheable(true);
        return query.list();
    }

    public String getSQL(String HQL, SearchMap searchMap)
    {
        StringBuffer tempHQL = new StringBuffer(HQL);
        boolean addWhere = false;
        if(HQL.toLowerCase().indexOf("where") < 0)
            addWhere = false;
        else
            addWhere = true;
        String tempSearchMap = searchMap.toHQL();
        if(tempSearchMap.length() > 0)
        {
            if(!addWhere)
            {
                tempHQL.append(" where ");
                addWhere = false;
            }
            if(!tempHQL.toString().trim().toLowerCase().endsWith("and") && !tempHQL.toString().trim().toLowerCase().endsWith("where"))
                tempHQL.append(" and ");
            tempHQL.append(tempSearchMap);
        }
        if(HQL.indexOf("count(*)") == -1)
        {
            int i = 0;
            for(Iterator iterator = searchMap.getOrderList().iterator(); iterator.hasNext();)
            {
                String order[] = (String[])iterator.next();
                if(i == 0)
                    tempHQL.append(" order by ");
                else
                    tempHQL.append(",");
                tempHQL.append(order[0]);
                if(order[1] != null)
                {
                    tempHQL.append(" ");
                    if("DESC".equalsIgnoreCase(order[1]))
                        tempHQL.append("desc");
                    else
                    if("ASC".equalsIgnoreCase(order[1]))
                        tempHQL.append("asc");
                    else
                        throw new RuntimeException((new StringBuilder("\u6CA1\u5B9A\u4E49\u7684\u6392\u5E8F\u7C7B\u578B:")).append(order[1]).toString());
                }
                i++;
            }

        }
        return tempHQL.toString();
    }

    public boolean isExist(Serializable id, String propertyName, String propertyValue, Class objectClass)
    {
        return isExistAnd(id, new String[] {
            propertyName
        }, new String[] {
            propertyValue
        }, objectClass);
    }

    public boolean isExistAnd(Serializable id, String propertyNames[], String propertyValues[], Class objectClass)
    {
        long count = 0L;
        SearchMap searchMap = new SearchMap();
        if(id != null)
            searchMap.notEq("id", id);
        for(int i = 0; i < propertyNames.length; i++)
            searchMap.eq(propertyNames[i], propertyValues[i]);

        count = getCount(searchMap, objectClass);
        return count > 0L;
    }

    public List isExistOr(Serializable id, String propertyNames[], String propertyValues[], Class objectClass)
    {
        throw new RuntimeException("\u6682\u4E0D\u652F\u6301isRepeatOr");
    }

    public int executeHql(String hql)
    {
        Session session = getSession();
        Query query = session.createQuery(hql);
        return query.executeUpdate();
    }

    public int executeSql(String sql)
    {
        Session session = getSession();
        SQLQuery sqlQuery = session.createSQLQuery(sql);
        return sqlQuery.executeUpdate();
    }

    public List querySql(String sql)
    {
        Session session = getSession();
        SQLQuery sqlQuery = session.createSQLQuery(sql);
        return sqlQuery.list();
    }

    static int[] swicthUtilVType()
    {
//        $SWITCH_TABLE$cn$com$ecinc$util$VType;
//        if($SWITCH_TABLE$cn$com$ecinc$util$VType == null) goto _L2; else goto _L1
//_L1:
//        return;
//_L2:
//        JVM INSTR pop ;
    	
    	
        int ai[] = new int[VType.values().length];
        try
        {
            ai[VType.BigDecimal.ordinal()] = 4;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Boolean.ordinal()] = 5;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Byte.ordinal()] = 12;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Date_sql.ordinal()] = 7;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Date_sybase.ordinal()] = 9;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Date_util.ordinal()] = 11;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Double.ordinal()] = 3;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Float.ordinal()] = 2;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Integer.ordinal()] = 1;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Long.ordinal()] = 10;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Short.ordinal()] = 13;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.String.ordinal()] = 6;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Timestamp.ordinal()] = 8;
        }
        catch(NoSuchFieldError _ex) { }
        try
        {
            ai[VType.Unvalid.ordinal()] = 14;
        }
        catch(NoSuchFieldError _ex) { }
        return utilVTypes = ai;
    }

    private static Log logger = LogFactory.getLog(cn.com.pusai.common.dao.impl.BaseDAOHibernate.class);
    private static int utilVTypes[];

}
